﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using Petra.Gis.Geometry;
using Petra.Gis.Geometry.Support;
using Petra.Gis.DataServices.WKT.Support;

namespace Petra.Gis.DataServices.WKT
{

  /// <summary>
  /// represents WKT regex based text parser that 
  /// can build RegexGeometry instance from given input WKT geometry string
  /// </summary>
  public partial class RegexGeometryParser
  {



    public enum PreferedRegexTypeEnum
    { 
      HighPerformance = 0,
      PreciseValidation = 1
    }


    private Dictionary<string, int> _GroupPositions;

    private Regex r;
    private Match m;
    private static Regex _geomNameRgx;



    /// <summary>
    /// static constructor initiate internal dictionary with regex patterns for each geometry type
    /// single place init is better for support
    /// </summary>
    static RegexGeometryParser() 
    {

      //this dictionary MUST keep in this order !!!
      //because getGeometryName function relies on this order
      ImplementedTypes = new List<WKTGeometryType>();
      ImplementedTypes.Add(WKTGeometryType.GeometryCollection);
      ImplementedTypes.Add(WKTGeometryType.Point);
      ImplementedTypes.Add(WKTGeometryType.LineString);
      ImplementedTypes.Add(WKTGeometryType.Polygon);
      ImplementedTypes.Add(WKTGeometryType.MultiPoint);
      ImplementedTypes.Add(WKTGeometryType.MultiLineString);
      ImplementedTypes.Add(WKTGeometryType.MultiPolygon);

      prepareRegexExpressions();

    }



    /// <summary>
    /// get list of geometry types that this parser can parse
    /// </summary>
    public static List<WKTGeometryType> ImplementedTypes
    { get; private set; }




    ///// <summary>
    ///// get/set prefered method for geometry data load from text.
    ///// Regex parser is timeconsuming so this lets choose between
    ///// higher performance with worse WKT text integrity check
    ///// and lower performance with great integrity check.
    ///// </summary>
    //public static PreferedRegexTypeEnum PreferedTextParser
    //{ get; set; }




    public RegexGeometryParser(WKTGeometryType geomType)
      : this(geomType, PreferedRegexTypeEnum.PreciseValidation)
    { }




    public RegexGeometryParser(WKTGeometryType geomType, PreferedRegexTypeEnum regexType)
    {
      if (regexType == PreferedRegexTypeEnum.PreciseValidation)
        r = RegexGeometryParser.getValidationRegex[geomType];
      else
        r = RegexGeometryParser.getFastRegex[geomType];

    }



    /// <summary>
    /// get/set prefered method for geometry data load from text.
    /// Regex parser is timeconsuming so this lets choose between
    /// higher performance with worse WKT text integrity check
    /// and lower performance with great integrity check.
    /// </summary>
    public PreferedRegexTypeEnum PreferedTextParser
    { get; private set; }



    public RegexGeometry ParseGeometry(ref string inputStr)
    {

      m = r.Match(inputStr);

      if (m.Length < 1)
        throw new ArgumentException("invalid input string for wkt", "inputStr");

      if((m.Groups["coordlist"].Captures.Count % 2) != 0)
        throw new ArgumentException("invalid input string for wkt", "inputStr");

      _GroupPositions = new Dictionary<string,int>();

      return new RegexGeometry(this);

    }




    public Match RegexMatch
    {
      get { return m; }
    }




    public int GetStartByCapture(string GroupName, int subgeomStart)
    {
      int startPos;

      try { startPos = _GroupPositions[GroupName]; }
      catch { _GroupPositions.Add(GroupName, 0); startPos = 0; }

      CaptureCollection cc = m.Groups[GroupName].Captures;

      int _start;
      for (_start = startPos; _start < cc.Count; _start++)
        if (subgeomStart < cc[_start].Index)
          break;

      _GroupPositions[GroupName] = _start;
      return _start;

    }




    public int GetEndByCapture(string GroupName, int subgeomEnd)
    {

      int startPos;

      try { startPos = _GroupPositions[GroupName]; }
      catch { _GroupPositions.Add(GroupName, 0); startPos = 0; }

      CaptureCollection cc = m.Groups[GroupName].Captures;

      int _end;

      //get end coord index
      for (_end = startPos; _end < cc.Count; _end++)
        if (subgeomEnd < cc[_end].Index)
          break;

      _end--;
      _GroupPositions[GroupName] = _end;
      return _end;
    }



    public static WKTGeometryType GetGeometryType(ref string inputStr)
    {
      //string pattern;
      //foreach (KeyValuePair<WKTGeometryType, string> kvp in getWktName)
      //{
      //  pattern = @"(?<geometryname>^[w]*" + kvp.Value + ")";
      //  //pattern = @"^[w]*" + kvp.Value;

      //  Regex r = new Regex(pattern);

      //  if (r.IsMatch(inputStr))
      //    return kvp.Key;
      //}

      Match _geomNameMt = _geomNameRgx.Match(inputStr);

      if (_geomNameMt.Success)
        return _geomNameMt.Groups["geometryname"].Captures[0].Value;

      else
        throw new ArgumentException("invalid input string, not a WKB text", "inputStr");
    }

  }

}
